39. Polígonos regulares

Asume que dispones de las siguientes funciones:

Función Descripción
``avanzar (puntos)` ` Avanza pintando una línea el número de puntos que indica el argumento.
girar(a ngulo) Gira los radianes que indica el argumento. Positivo indica giro a la derecha, negativo indica giro a la izquierda.
comenza r() Sitúa el lápiz en el punto de partida sin pintar nada.
saltar( puntos) Avanza sin pintar el número de puntos que indica el argumento.

Define una función poligono con dos argumentos que indican el número de lados y la longitud del lado respectivamente. La función debe dibujar un polígono regular con el número de lados indicados. Inicialmente el lápiz está orientado hacia la derecha.

39.1. Ejemplo de funcionamiento:

>>> poligono(5, 80)
Pentágono

Pentágono

39.2. Solución

Primero copiamos la implementación de las funciones de dibujo.

from IPython.display import SVG,display
from math import pi, sin, cos

def avanzar(puntos):
    global current_pos, current_drawing
    pos1 = current_pos
    saltar(puntos)
    current_drawing += line(pos1, current_pos)

def saltar(puntos):
    global current_pos, current_angle
    x, y = current_pos
    current_pos = x + puntos*cos(current_angle), y + puntos*sin(current_angle)

def girar(radianes):
    global current_angle
    current_angle += radianes

def goto(x,y):
    global current_pos
    current_pos = (x,y)

def comenzar():
    global current_pos, current_angle
    current_pos = (100,100)
    current_angle = 0.

def limpiar():
    global current_drawing
    current_drawing = ''
    comenzar()

def dibujo():
    global current_drawing
    ret = SVG('''<svg width="200" height="200" viewBox="0 0 200 200"
                      xmlns="http://www.w3.org/2000/svg">{}</svg>'''\
               .format(current_drawing))
    limpiar()
    display(ret)

def line(p1, p2):
    (x1, y1), (x2, y2) = p1, p2
    return '''<line x1="{}" y1="{}"
                    x2="{}" y2="{}"
                    stroke-width="1" stroke="black"/>'''.format(x1,y1,x2,y2)

limpiar()

La función para crear un polígono es un simple bucle.

from math import pi

def poligono(n, lado):
    for i in range(n):
        avanzar(lado)
        girar(-2*pi/n)

Vamos a probarla.

poligono(5,40)
dibujo()

40. Estrella cirscunscrita

Siguiendo con el ejemplo del polígono define una función estrella con dos argumentos (número de lados y longitud de cada segmento) que dibuja una estrella circunscrita en el polígono, como muestran los ejemplos a continuación. Observa que se trata de la estrella resultante de saltar uno de cada dos vértices. Observa también que cuando el número de lados es par la estrella está compuesta por dos líneas poligonales de la mitad de lados.

Si solo funciona con número impar de lados se asumirá correcto pero se descontará un 20% de la calificación.

40.1. Ejemplo de funcionamiento

>>> estrella(5,150)
Pentagrama

Pentagrama

>>> estrella(6,150)
Pentagrama

Pentagrama

40.2. Solución

La estrella con n impar es igual ue el polígono, tan solo cambia el ángulo. Vamos a extraer la funcionalidad común en una función poligonal. El caso impar se descompone en dos líneas poligonales no conectadas.

Ángulo de giro en estrella

Ángulo de giro en estrella

def estrella(n, lado):
    angulo = -4*pi/n
    if n%2 != 0:
        poligonal(n, lado, angulo)
        return
    poligonal(n//2, lado, angulo)
    siguiente_vertice(n,lado)
    poligonal(n//2, lado, angulo)

def poligonal(n,lado,angulo):
    for i in range(n):
        avanzar(lado)
        girar(angulo)

La parte más difícil es cómo viajar hasta el siguiente vértice una vez que hemos terminado de dibujar la primera línea poligonal de las estrellas con n par. Hay que hacer un poco de razonamiento geométrico para calcular el giro y salto necesario. Basta calcular los ángulos \(\alpha\) y \(\beta\) de la figura y el ángulo de giro será simplemente la semidiferencia de ambos.

Ángulos en caso de n par

Ángulos en caso de n par

def siguiente_vertice(n, lado):
    a = pi/n
    girar(a)
    saltar(lado/2/cos(a))
    girar(-3*a)

Y la probamos

estrella(5,50)
dibujo()
estrella(6,50)
dibujo()

41. Mosaicos

Suponiendo que dispones de la función poligono a la que se refiere el primer ejercicio y las funciones de dibujo descritas en el mismo ejercicio definir una función rosa que dibuja polígonos en cada lado de otro polígono central formando una rosa como la de la figura.

La función rosa debe tener dos argumentos similares a los de poligono, es decir, el número de lados y el tamaño del lado.

41.1. Ejemplo de funcionamiento:

>>> rosa(5, 40)
Rosa pentagonal

Rosa pentagonal

>>> rosa(7, 40)
Rosa heptagonal

Rosa heptagonal

41.2. Solución

El problema es completamente análogo a la función que construye el polígono, pero en lugar de avanzar, simplemente llama a poligono y avanza un lado, y el giro lo realiza en el otro sentido.

def rosa(n, lado):
    for i in range(n):
        poligono(n, lado)
        saltar(lado)
        girar(2*pi/n)

Vamos a probarla.

rosa(6,20)
dibujo()

42. Curvas fractales

El copo de nieve de Koch es una curva fractal muy sencilla de obtener con ayuda de una función recursiva.

Define una función copo con dos argumentos. El primero es el ancho total del copo de nieve (en puntos), el segundo es un índice que limita la recursión. La función debe dibujar el copo de Koch con las funciones de dibujo descritas en el primer ejercicio.

42.1. Ejemplo de funcionamiento

El dibujo siguiente muestra el resultado de ``copo(300,n)`` con valores para n de 0, 1, 2, 4.

Copo de Koch para n=0,1,2,4

Copo de Koch para n=0,1,2,4

42.2. Solución

La forma más sencilla es dibujar 3 veces la curva de Koch con distintos ángulos.

from math import pi

def copo(lado, n):
    for i in (0,1,2):
        koch(lado,n)
        girar(2*pi/3)

def koch(lado, n):
    if n == 0:
        avanzar(lado)
        return
    for angulo in (-pi/3, 2*pi/3, -pi/3, 0):
        koch(lado/3, n-1)
        girar(angulo)

A probarla.

goto(50,50)
copo(100,4)
dibujo()
Next Section - 43. Ley de Benford